﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024 LiLong                                                   **
**  This file is part of GnssLogs.                                              **
**                                                                              **
**  GnssLogs is free software: you can redistribute it and/or modify            **
**  it under the terms of the GNU Lesser General Public License as published by **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  GnssLogs is distributed in the hope that it will be useful,                 **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU Lesser General Public License for more details.                         **
**                                                                              **
**  You should have received a copy of the GNU Lesser General Public License    **
**  along with GnssLogs.  If not, see <https://www.gnu.org/licenses/>.          **
**********************************************************************************/
#pragma once

#include "../ALIGNBSLNENU.h"
#include "LogHeaderDecoder.h"

namespace GnssLogs
{
namespace ALIGNBSLNENUDecoder
{
using namespace tao::pegtl;
using Sync   = TAO_PEGTL_STRING("#ALIGNBSLNENUA");
using Header = LogHeaderDecoder::SyncExpression<Sync>;
// clang-format off
struct SolStatus : ascii::identifier {};
struct PosType : ascii::identifier {};
struct East : Floating {};
struct North : Floating {};
struct Up : Floating {};
struct EastSigma : Floating {};
struct NorthSigma : Floating {};
struct UpSigma : Floating {};
struct RoverID : StringLiteral {};
struct BaseID : StringLiteral {};
struct SVs : star<digit> {};
struct SolnSVs : star<digit> {};
struct Obs : star<digit> {};
struct Multi : star<digit> {};
struct Reversed : star<xdigit> {};
struct ExtSolStat : star<xdigit> {};
struct GalileoAndBeiDouSigMaskRule : star<xdigit> {};
struct GpsAndGLONASSSigMaskRule : star<xdigit> {};
// clang-format on

using Expression = seq<Header,
                       SolStatus,
                       Split,
                       PosType,
                       Split,
                       East,
                       Split,
                       North,
                       Split,
                       Up,
                       Split,
                       EastSigma,
                       Split,
                       NorthSigma,
                       Split,
                       UpSigma,
                       Split,
                       RoverID,
                       Split,
                       BaseID,
                       Split,
                       SVs,
                       Split,
                       SolnSVs,
                       Split,
                       Obs,
                       Split,
                       Multi,
                       Split,
                       Reversed,
                       Split,
                       ExtSolStat,
                       Split,
                       GalileoAndBeiDouSigMaskRule,
                       Split,
                       GpsAndGLONASSSigMaskRule,
                       one<'*'>,
                       CRC32,
                       Tail>;

template<typename T>
struct Action
{
};

template<>
struct Action<Header> : LogHeaderDecoder::LogHeaderHelperNoSetValue
{
};

template<>
struct Action<SolStatus> : EnumHelper<Action<SolStatus>, SolutionStatus>
{
    static void setValue(ALIGNBSLNENU::Data& data, SolutionStatus e) { data.solStatus = e; }
};

template<>
struct Action<PosType> : EnumHelper<Action<PosType>, PositionOrVelocityType>
{
    static void setValue(ALIGNBSLNENU::Data& data, PositionOrVelocityType e) { data.posType = e; }
};

template<>
struct Action<East> : DoubleHelper<Action<East>>
{
    static void setValue(ALIGNBSLNENU::Data& data, double value) { data.east = value; }
};

template<>
struct Action<North> : DoubleHelper<Action<North>>
{
    static void setValue(ALIGNBSLNENU::Data& data, double value) { data.north = value; }
};

template<>
struct Action<Up> : DoubleHelper<Action<Up>>
{
    static void setValue(ALIGNBSLNENU::Data& data, double value) { data.up = value; }
};

template<>
struct Action<EastSigma> : FloatHelper<Action<EastSigma>>
{
    static void setValue(ALIGNBSLNENU::Data& data, float value) { data.eastSigma = value; }
};

template<>
struct Action<NorthSigma> : FloatHelper<Action<NorthSigma>>
{
    static void setValue(ALIGNBSLNENU::Data& data, float value) { data.northSigma = value; }
};

template<>
struct Action<UpSigma> : FloatHelper<Action<UpSigma>>
{
    static void setValue(ALIGNBSLNENU::Data& data, float value) { data.upSigma = value; }
};

template<>
struct Action<RoverID> : StringHelper<Action<RoverID>>
{
    static void setValue(ALIGNBSLNENU::Data& data, const std::string& value) { data.roverID = value; }
};

template<>
struct Action<BaseID> : StringHelper<Action<BaseID>>
{
    static void setValue(ALIGNBSLNENU::Data& data, const std::string& value) { data.baseID = value; }
};

template<>
struct Action<SVs> : IntHelper<Action<SVs>, uint8_t>
{
    static void setValue(ALIGNBSLNENU::Data& data, uint8_t value) { data.svs = value; }
};

template<>
struct Action<SolnSVs> : IntHelper<Action<SolnSVs>, uint8_t>
{
    static void setValue(ALIGNBSLNENU::Data& data, uint8_t value) { data.solnSVs = value; }
};

template<>
struct Action<Obs> : IntHelper<Action<Obs>, uint8_t>
{
    static void setValue(ALIGNBSLNENU::Data& data, uint8_t value) { data.obs = value; }
};

template<>
struct Action<Multi> : IntHelper<Action<Multi>, uint8_t>
{
    static void setValue(ALIGNBSLNENU::Data& data, uint8_t value) { data.multi = value; }
};

template<>
struct Action<Reversed> : IntHelper<Action<Reversed>, uint8_t, 16>
{
    static void setValue(ALIGNBSLNENU::Data& data, uint8_t value) { data.reversed = value; }
};

template<>
struct Action<ExtSolStat> : ExtendedSolutionStatusHelper<Action<ExtSolStat>>
{
    static void setValue(ALIGNBSLNENU::Data& data, ExtendedSolutionStatus value) { data.extSolStat = value; }
};

template<>
struct Action<GalileoAndBeiDouSigMaskRule> : IntHelper<Action<GalileoAndBeiDouSigMaskRule>, uint8_t, 16>
{
    static void setValue(ALIGNBSLNENU::Data& data, uint8_t value) { data.galileoAndBeiDouSigMask = GalileoAndBeiDouSignalUsedMasks(value); }
};

template<>
struct Action<GpsAndGLONASSSigMaskRule> : IntHelper<Action<GpsAndGLONASSSigMaskRule>, uint8_t, 16>
{
    static void setValue(ALIGNBSLNENU::Data& data, uint8_t value) { data.gpsAndGLONASSSigMask = GPSAndGLONASSSignalUsedMasks(value); }
};

template<>
struct Action<CRC32> : CRC32Helper<Action<CRC32>>
{
    static void setValue(ALIGNBSLNENU::Data& data, uint32_t value) { data.crc32 = value; }
};
} // namespace ALIGNBSLNENUDecoder
} // namespace GnssLogs